from ckeditor.fields import RichTextField
from django.db import models
# from django_jsonfield_backport.models import JSONField
# from django_mysql.models import JSONField  # 注意：JSONField在django_mysql中
from django.utils.datetime_safe import datetime
from django.db.models import JSONField


class HotSearchWords(models.Model):
    """
    热搜词  后期机器学习
    """
    name = models.CharField(verbose_name='热搜词', max_length=10, help_text='商品名称')
    sort = models.SmallIntegerField(verbose_name='排序')
    is_delete = models.SmallIntegerField(verbose_name='弃用', default=0)
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)


class UserSearchWords(models.Model):
    """
    为了提高效率 这是一个异步任务  自动关联爬虫
    用户搜索记录
    采用 redis-through
    """
    name = models.CharField(verbose_name='热搜词', max_length=10, help_text='商品名称')
    search_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)


class GoodCategory(models.Model):
    """
    商品分类
    is_hot：分类可以标红
    is_banner：在横栏显示
    # 仅三级分类    如果无限极 可以 is_parent 来表示   1 有父级
    """
    CATEGORY_TYPE = (
        (1, '一级分类'),
        (2, '二级分类'),
        (3, '三级分类')
    )
    name = models.CharField(verbose_name='分类名称', max_length=50, help_text='分类名称')
    # modify_name = models.CharField(verbose_name='中文商品名称', max_length=50, help_text='商品名称')
    # 这里没必要获取首字母缩写
    # en_name = models.CharField(verbose_name='英文名称', max_length=100)
    category_type = models.IntegerField(verbose_name='分类类型', choices=CATEGORY_TYPE)
    # 自关联
    parent_category = models.ForeignKey('self', null=True, blank=True, related_name='sub_cat', default='',
                                        verbose_name='父级分类',
                                        on_delete=models.CASCADE)
    is_banner = models.SmallIntegerField(verbose_name='是否横幅', default=0)
    # is_display = models.SmallIntegerField(verbose_name='是否显示', default=0)

    sort = models.SmallIntegerField(verbose_name='排序', default=0)
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)

    class Meta:
        verbose_name = '商品分类'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class GoodBrand(models.Model):
    """
    商标/品牌
    一级分类下面的品牌
    # 新增品牌首字母

    """
    category = models.ForeignKey(to=GoodCategory, verbose_name='商品分类', related_name='banner', default='', null=True,
                                 blank=True,
                                 on_delete=models.CASCADE)

    # 三个
    # 不管是日文 英文还是其他文 都是  en_name
    en_name = models.CharField(verbose_name='英文名称', max_length=100, default='')
    # jp_name = models.CharField(verbose_name='日文名称', max_length=100, default='')
    zh_name = models.CharField(verbose_name='中文名称', max_length=100, default='')

    # 只有推荐才在  后台展现
    is_recommend = models.SmallIntegerField(default=0, verbose_name='是否推荐')
    letter = models.CharField(verbose_name='品牌首字母', max_length=2)
    desc = models.TextField(verbose_name='品牌描述', default='')
    sort = models.SmallIntegerField(verbose_name='排序', default=0)
    # upload_to='brands/%Y/%m/%d',
    image = models.URLField(verbose_name='品牌logo', default='')
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)

    class Meta:
        verbose_name = '品牌名'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.en_name


# 提高效率 不采用多对多  而是采用spg 管理
# class GoodTags(models.Model):
#     """
#     # 废弃 使用 spg统一管理
#     该标签库 用于搜索界面的分类检索
#     商品搜索标签
#     """
#     en_name = models.CharField(verbose_name='英文名称', max_length=100, default='')
#     jp_name = models.CharField(verbose_name='日文名称', max_length=100, default='')
#     is_hot = models.SmallIntegerField(verbose_name='是否hot', default=0)
#     is_delete = models.SmallIntegerField(verbose_name='弃用', default=0)
#     add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)


class Source(models.Model):
    """
    商品采集源
    """
    name = models.CharField(verbose_name='来源名称', max_length=20)
    url = models.URLField(verbose_name='采集地址')


class SPG(models.Model):
    """
    品类表
    不是分类表  该表用来存储大类的共有属性
    即 把标签统一化
    """
    name = models.CharField(verbose_name='品类名称', max_length=20, unique=True)
    # 分区  1-100属于数码
    spg_id = models.CharField(verbose_name='品类编号', max_length=10, default=None, blank=True, null=True)

    def __str__(self):
        return self.name


class Attribute(models.Model):
    """
    这里维护
    颜色 鞋码 等信息
    """
    apg = models.ForeignKey(to=SPG, verbose_name='所属品类', on_delete=models.CASCADE, related_name='attribute_spg')
    # spa_id = models.CharField(verbose_name='属性编号', max_length=50, default=0)
    name = models.CharField(verbose_name='参数名称', max_length=100)
    # 是否多选 1 单选  2多选 3 唯一 删除该字段
    # multi_select = models.SmallIntegerField(default=1)
    inputType = models.SmallIntegerField(choices=((0, '手工录入'), (1, '从列表中选取')))
    # 可以为空
    inputList = models.TextField(verbose_name='属性值列表', null=True, blank=True)
    is_search = models.SmallIntegerField(verbose_name='是否检索', default=0)

    # is_handle = models.SmallIntegerField(verbose_name='是否支持手动新增', default=0)


class Param(models.Model):
    """
    使用  spg  后台加参数
    搜索页面的小标签
    参数表  需要动态维护一个表     一个品类对应多个参数
    规格 产地 等
    适用季节  适用人群  上市时间 等  属于一个大的spg
    # https://zq99299.github.io/mysql-tutorial/ali-new-retail/04/02.html#%E5%8F%82%E6%95%B0%E8%A1%A8%E7%BB%93%E6%9E%84%E5%9B%BE
    """
    apg = models.ForeignKey(to=SPG, verbose_name='所属品类', on_delete=models.CASCADE, related_name='param_spg')
    name = models.CharField(verbose_name='参数名称', max_length=100)
    # 是否多选 1 单选  2多选 3 唯一  删除该字段
    # multi_select = models.SmallIntegerField(default=1)
    inputType = models.SmallIntegerField(choices=((0, '手工录入'), (1, '从列表中选取')))
    inputList = models.TextField(verbose_name='属性值列表', null=True, blank=True)
    is_search = models.SmallIntegerField(verbose_name='是否检索', default=0)

    # is_handle = models.SmallIntegerField(verbose_name='是否支持手动新增', default=0)
    # spp_id = models.CharField(verbose_name='参数编号', max_length=10)
    # name = models.CharField(verbose_name='参数名称', max_length=10)
    # numeric = models.BooleanField(verbose_name='是否为数字参数', default=False)
    # unit = models.CharField(verbose_name='单位', max_length=20, default='')
    # generic = models.BooleanField(verbose_name='是否为通用参数', default=False)
    # searching = models.BooleanField(verbose_name='是否用于搜索', default=False)
    # segments = models.CharField(verbose_name='参数值720P\\1080P\\4K\8K', max_length=100)


class Product(models.Model):
    """
    将建立一个备用库来进行 爬取内容的存储  提高效率
    商品信息
    品类和商标 多对多
    # 实际需求  分类下面的品牌很重要   但是品牌下面的分类不太重要  可以多对多也可以一对多  新增多对多关系
    # 搜藏的是产品  对  这部分是对的

    # 搜索使用product接口
    # 首页直接对商品进行展示

    # 后台添加商品的时候和淘宝类似  先添加轮播图
    # 具体的产品一张图片即可  其他全部由详情页引导
    """

    spg = models.ForeignKey(to=SPG, verbose_name='所属品类,添加商品用', on_delete=models.CASCADE, related_name='spg_product')
    category = models.ForeignKey(to=GoodCategory, verbose_name='商品分类', related_name='category_product',
                                 on_delete=models.CASCADE)
    brand = models.ForeignKey(to=GoodBrand, verbose_name='商品商标', on_delete=models.CASCADE)
    source = models.ForeignKey(to=Source, verbose_name='来源', on_delete=models.CASCADE, default=4)

    # 这个应该单独训练
    # tag = models.ManyToManyField(to=GoodTags, verbose_name='商品标签')

    # 三方网站的sn
    # https://www.cosme-de.net/pd/products/ADN0141?product_no=ADN0215
    # 即ADN0141  product_no=ADN0215为商品  这个是唯一的的
    third_sn = models.CharField(verbose_name='商品编号', max_length=50, default='')
    # 雪花id  商品主序列号  models.BigIntegerField
    sn = models.BigIntegerField(verbose_name='商品id', unique=True)
    # 爬取链接 参考网站
    data_url = models.URLField(verbose_name='数据链接', default='')
    source_url = models.URLField(verbose_name='源链接', default='')
    #
    carousel = models.JSONField(blank=True, null=True)
    # 直接取
    # 该title作用于搜索  包含商品子表的所有关键字  通用名称
    # 这个是要的    搜索用  品牌名 英文+中文  放在这里 还有其他描述
    # 可以展示多个  直接选中
    # 展现的是 title + 各商品的title
    # 展示的商品 不是产品   点进去即默认选中
    title = models.CharField(verbose_name='商品名称', max_length=200)
    # 修改后的标题
    # modify_title = models.CharField(verbose_name='修改商品名称', max_length=200, default='')

    # 添加最大价格和最小价格
    # 目的  这个价格不是立即变动的  redis write_through 进行写入
    # 计算写入
    max_price = models.FloatField(verbose_name='最大价格', default=0)
    min_price = models.FloatField(verbose_name='最小价格', default=0)

    # 总的销量
    # 不要用关联查询  大大降低性能 定时统计插入
    total_sold = models.IntegerField(verbose_name='总销量', default=0)

    # 产品搜藏量  不用鉴权  redis 打入 对产品进行搜藏
    # 是否考虑  搜藏动态redis 写入
    fav_num = models.IntegerField(verbose_name='收藏数量', default=0)

    # 是否搜藏 用户鉴权
    # 由其他库存储
    # is_collect = models.SmallIntegerField(verbose_name='是否搜藏', default=0)

    # 给产品一个cover
    # cover = models.URLField(verbose_name='商品封面')
    # 商品图集由产品保存  商品只存储cover
    # 前端实现切换
    # 2021/06/10 添加逻辑  商品展示轮播图  具体产品只有一个cover
    # 即产品介绍 商品详情  数组存储
    # 逗号分割  可以为空
    images = models.TextField(verbose_name='轮播图', null=True, blank=True)

    # 商品展示图  可以不是直接取  images 的第一个
    # 如果为空取 images的第一个
    pic = models.URLField(verbose_name='图片链接',
                          default='https://oscimg.oschina.net/oscnet/up-e8efd92619f3862440063175740fb1fc18b.JPEG',
                          blank=True)

    # 商品简介  产品和商品都要有简介
    # 可以为空
    desc = models.TextField(null=True, blank=True)
    # 这个地方的cover 日本站的
    # cover = models.URLField(verbose_name='封面', default=None)

    # 新增参数  存储映射的数据
    # 存储属性和参数 选中的数据
    # 需要商品写入这连个属性 后台用
    # null 是针对数据库而言，如果 null=True, 表示数据库的该字段可以为空。
    # blank 是针对表单的，如果 blank=True，表示你的表单填写该字段的时候可以不填，比如 admin 界面下增加 model 一条记录的时候。直观的看到就是该字段不是粗体
    # 这里面保存的是 选中的数据
    # 注意属性是复选的  参数是单选的
    params = JSONField(blank=False)
    attrs = JSONField(blank=False)

    # 商品的详情
    # 放到 产品  所有的都放在一起
    detail = RichTextField(verbose_name='商品详情', null=True)
    # modify_detail = RichTextField(verbose_name='修改商品详情', default='')

    # 状态合并
    # 1 删除 2 促销 3 推荐 4 新品 5 上架 6 下架
    # 当状态为6  直接跳转页面
    # status = models.SmallIntegerField(verbose_name='状态',
    #                                   choices=((1, '删除'), (2, '促销'), (3, '推荐'), (4, '新品'), (5, '上架'), (6, '下架')),
    #                                   default=5)
    # 基本信息
    # 逻辑删除 上下架通用   产品商品 均可以删除
    is_delete = models.SmallIntegerField(verbose_name='逻辑删除', default=0)
    # 新增一个字段  促销  删除 给具体商品促销字段
    # is_promotion = models.SmallIntegerField(verbose_name='是否促销', default=0)
    # 只有推荐才在  后台展现  目前仅仅针对整个产品推荐
    is_recommend = models.SmallIntegerField(default=0, verbose_name='是否推荐')
    is_new = models.SmallIntegerField(default=0, verbose_name='是否新品  人为控制')

    # sort 排序
    sort = models.IntegerField(verbose_name='排序', default=0)
    # 单位 瓶 件
    unit = models.CharField(max_length=20, default='件')

    #
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)
    update_time = models.DateTimeField(verbose_name='更新时间', default=datetime.now)

    # 冗余字段
    # belong = models.CharField(verbose_name='商品归属', max_length=50)
    # good_status = models.CharField(verbose_name='商品状态', default="InStock", max_length=20)
    # rate = models.FloatField(verbose_name='评分')
    # comments = models.IntegerField(verbose_name='评论数')
    # en_brand = models.CharField(verbose_name='英文品牌', max_length=50)
    # jp_brand = models.CharField(verbose_name='日文品牌', max_length=200)
    # tags = models.CharField(verbose_name='商品标签', max_length=200, default='')

    class Meta:
        verbose_name = '商品表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title


class Good(models.Model):
    """
    定义规格和产品
    规格/型号 16G 32G 64G等
    产品/款式 即颜色等  肯定有的
    # 下单的时候 直接新建一个  还是修改的时候新建一个

    # 前端url应该是 商品 而不是产品

    # 最终展示的应该是 品牌名 + 商品标题

    # 这里的规格   暂时使用京东
    # 对于京东  每个属性都具有不同的详情描述  给出一个默认的cover 而且每个属性 单独具有商品轮播图
    # 对于淘宝  所有属性共用一个详情描述   淘宝则是公用商品轮播图  每个属性具有一个cover
    # 淘宝和京东   product 的title 其主要的搜索作用

    # 我们采用优化设计
    # 1. 商品详情 采用统一的
    # 2. 产品使用cover 不使用 images  可以为空  则取第一个商品
    # 3. 具体商品可以加轮播
    """
    be_product = models.ForeignKey(to=Product, verbose_name='商品', related_name='goods', related_query_name='product',
                                   on_delete=models.CASCADE)

    # 商品标题
    # 0528采用动态json
    # classify = models.CharField(verbose_name='精确的商品名称', max_length=200)
    # modify_classify = models.CharField(verbose_name='修改商品名称', max_length=200, default='')

    # 采用雪花id
    # 根据特殊性  一个产品可能来自多个站的数据
    # 商品 sku_id  BigIntegerField
    sku_id = models.BigIntegerField(verbose_name='商品编号', unique=True)
    # 日本站具体的sku值
    # https://www.cosme-de.net/pd/products/YS00627?product_no=YS00629
    # 即 product_no
    source_id = models.CharField(verbose_name='源id', max_length=50, default='')
    # 这个值是要存的  因为商品对应唯一各链接   产品的话用一个就可以了  因为商品详情是一样的
    # 国内数据源链接
    data_url = models.URLField(verbose_name='数据链接', default='')
    # 日本站链接
    source_url = models.URLField(verbose_name='源链接', default='')

    # 参数JSON
    # {"版本类型":"中国大陆", "存储容量":"16GB", "套餐类型":"套餐一", "机身颜色":"黑色"}
    # 这里直接和后台做映射就好了
    # 采用下面的方式进行存储    key/value
    # [{\"key\":\"产品\",\"value\":\"所属\"},{\"key\":\"容量\",\"value\":\"80ML\"}]
    params = JSONField()
    # 产品/款式   这个地方不是标题  比如10ml 20ml等等 颜色等等
    # good_type = models.CharField(verbose_name='商品型号', max_length=200)
    # 型号可能不存在  比如裤子的尺码
    # good_model = models.CharField(verbose_name='商品型号', max_length=200)

    # 下面的两个字段先保留
    # 详解不属于产品  属于商品
    desc = models.TextField(verbose_name='商品简介', default='')
    # 商品详情
    detail = RichTextField(verbose_name='商品详情', default='')

    # 有参考 直接后台编辑
    # modify_desc = models.TextField(verbose_name='修改商品简介', default='')

    # 商品几个基本状态  0 就是免费  是几邮费就是多少
    # 1 包邮 2 上架 3 免邮 4 下架 5 新品 6 热卖 7 促销  8 删除
    # 状态为4 提示下架
    # 商品不具有新品字段   删除
    # is_new = models.SmallIntegerField(verbose_name='是否新品', default=2)
    is_free = models.SmallIntegerField(verbose_name='是否包邮', default=0)

    # 注意下架和删除不一样
    #   `status` tinyint(4) NOT NULL COMMENT '状态 -1=>下架,1=>上架,2=>预售,0=>未上架',
    is_sold = models.SmallIntegerField(verbose_name='是否下架', default=0)
    # 物理删除
    is_delete = models.SmallIntegerField(verbose_name='逻辑删除', default=0)

    # 机器学习算出分析  接口直接查good
    is_hot = models.SmallIntegerField(verbose_name='是否热卖', default=0)
    # 是否进行促销
    is_promotion = models.SmallIntegerField(verbose_name='是否促销', default=0)

    # 由参数表存入  json
    # 存储共有属性   分辨率 材质等
    # https://blog.csdn.net/u012111465/article/details/89857085
    # https://django-mysql.readthedocs.io/en/latest/checks.html#django-mysql-w003-utf8mb4
    # 使用utf8mb4_unicode_ci
    # 还要优化  应该是由品类库的参数  遍历生成多个商品  不然库存没法搞
    # param = JSONField()

    # 商品库存
    good_num = models.IntegerField('商品数量', default=10000)
    # redis write through 5分钟同步一次
    sold_num = models.IntegerField(verbose_name='销售数量', default=0)

    # 具体商品展示cover
    cover = models.URLField(verbose_name='商品封面',
                            default='https://oscimg.oschina.net/oscnet/up-e8efd92619f3862440063175740fb1fc18b.JPEG',
                            blank=True)
    # 图片由json存储 只存储单张图片  删除该字段    具体商品只有一张图片
    # images = JSONField()
    # cover = models.URLField(verbose_name='商品封面')

    # 两个价格  这里多一个
    market_price = models.FloatField(verbose_name='市场价格', default=0)
    # 市场价
    sold_price = models.FloatField(verbose_name='销售价格', default=0)
    # 三方店铺  爬虫价格
    third_price = models.FloatField(verbose_name='爬取网站价格', default=0)

    # 2021/05/27 新加
    # 点击量浏览量 数据具体商品  而不是产品  由redis定时同步
    click_num = models.IntegerField(verbose_name='点击数量', default=0)

    # 邮费  根据重量计算  按 克 存储
    weight = models.SmallIntegerField(verbose_name='重量', default=1000)
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)
    update_time = models.DateTimeField(verbose_name='更新时间', default=datetime.now)

    def __str__(self):
        return self.data_url


class IndexCarouselGood(models.Model):
    """
    轮播商品
    存放首页轮播图片
    # 可以考虑和商品关联
    # 这个部分 对首页轮播进行设置
    其他的放在专题库
    """
    # 2021/06/13  只能从库中商品选择 添加商品的时候进行选择  关联产品
    # 对产品进行关联
    # product = models.ForeignKey(to=Product, verbose_name='所属商品', on_delete=models.CASCADE)
    # 新加字段  一个产品可以有多个活动
    # product = models.ForeignKey(to=Product, verbose_name='轮播关联', on_delete=models.CASCADE,
    #                             related_name='carousel_product', null=True, blank=True)
    name = models.CharField(verbose_name='广告名称', max_length=100)
    type = models.SmallIntegerField(verbose_name='默认pc  1pc  2移动', default=1)
    # 设计一个默认图片
    pic = models.URLField(verbose_name='轮播图', default='')
    sort = models.IntegerField(default=1, verbose_name='轮播顺序')
    status = models.SmallIntegerField(verbose_name='是否有效', default=1)
    # url = models.URLField(verbose_name='产品链接')
    note = models.CharField(verbose_name='备注', max_length=200, null=True)
    # redis 打入
    clickCount = models.IntegerField(verbose_name='点击次数', default=0)
    startTime = models.DateTimeField(verbose_name='开始时间', default=datetime.now)
    endTime = models.DateTimeField(verbose_name='结束时间', default=datetime.now)
    add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)

    class Meta:
        verbose_name = '轮播商品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 提高效率 弃用
# class GoodCarouselImage(models.Model):
#     """
#     商品商品轮播图片
#     # 这里轮播 对应产品即可
#     # 该字段可以升级json保存
#     """
#     good = models.ForeignKey(to=Product, verbose_name='所属商品', related_name='images', on_delete=models.CASCADE)
#     image = models.URLField(verbose_name='商品封面')
#     add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)
#
#     class Meta:
#         verbose_name = '轮播图片'
#         verbose_name_plural = verbose_name
#
#     def __str__(self):
#         return self.good.title


class CategoryIndexAD(models.Model):
    """
    目录广告位置
    存放 每个分类推荐的商品
    这个地方根据每天的销量 自动排序   取redis的数据  一天已更新
    自动生成对应比列的图片
    """
    category = models.ForeignKey(to=GoodCategory, related_name='category', verbose_name='商品分类',
                                 on_delete=models.CASCADE)
    good = models.ForeignKey(to=Product, related_name='good', verbose_name='所属商品', on_delete=models.CASCADE)
    image = models.ImageField(verbose_name='轮播图', upload_to='ad/%Y/%m/%d')

    class Meta:
        verbose_name = '广告配置'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.good.title


class ProductOld(models.Model):
    """
    用于快照备份
    后期优化 暂时不做  非b2c 单向

    """
    old_id = models.IntegerField(verbose_name='old id')
    spg = models.OneToOneField(to=SPG, verbose_name='所属品类,添加商品用', on_delete=models.CASCADE)
    category = models.ForeignKey(to=GoodCategory, verbose_name='商品分类', on_delete=models.CASCADE)
    brand = models.ForeignKey(to=GoodBrand, verbose_name='商品商标', on_delete=models.CASCADE)
    source = models.ForeignKey(to=Source, verbose_name='来源', on_delete=models.CASCADE)
    sn = models.CharField(verbose_name='商品编号', max_length=50)
    title = models.CharField(verbose_name='商品名称', max_length=200)
    cover = models.URLField(verbose_name='商品封面')
    desc = models.TextField(verbose_name='商品简介', default='')
    detail = RichTextField(verbose_name='商品详情', default='')
    bak_time = models.DateTimeField(verbose_name='备份时间', default=datetime.now)

    class Meta:
        verbose_name = '商品表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title


class GoodOld(models.Model):
    """
    备份表
    """
    old_id = models.IntegerField(verbose_name='old id')
    be_good = models.ForeignKey(to=ProductOld, verbose_name='商品', related_name='params', on_delete=models.CASCADE)
    classify = models.CharField(verbose_name='精确的商品名称', max_length=200)
    sku_id = models.CharField(verbose_name='商品编号', max_length=50)
    good_type = models.CharField(verbose_name='商品型号', max_length=50)
    good_model = models.CharField(verbose_name='商品型号', max_length=50)
    param = JSONField()
    images = JSONField()
    market_price = models.FloatField(verbose_name='市场价格', default=0)
    shop_price = models.FloatField(verbose_name='销售价格', default=0)
    bak_time = models.DateTimeField(verbose_name='备份时间', default=datetime.now)
